package com.dhh.sky.service;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import org.json.JSONObject;
import com.dhh.sky.R;
import com.dhh.sky.SDAApplication;
import com.dhh.sky.activity.OperationListActivity;
import com.dhh.sky.model.Operation;
import com.dhh.sky.util.CUtil;
import com.dhh.sky.util.Config;
import com.dhh.sky.util.Constant;
import com.dhh.sky.util.FileManager;
import com.dhh.sky.util.JsonKeys;
import com.dhh.sky.util.OperationManager;
import com.microsoft.live.LiveAuthClient;
import com.microsoft.live.LiveAuthException;
import com.microsoft.live.LiveAuthListener;
import com.microsoft.live.LiveConnectClient;
import com.microsoft.live.LiveConnectSession;
import com.microsoft.live.LiveOperation;
import com.microsoft.live.LiveOperationException;
import com.microsoft.live.LiveStatus;
import com.microsoft.live.LiveUploadOperationListener;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;

public class UploadOperationService extends IntentService {
	private Notification notification;
	private NotificationManager notificationManager;
	private OperationManager om;
	private FileManager fm;
	private String path;
	private LiveOperation operation;
	private Operation op;
	private SDAApplication app;
	
	public UploadOperationService(){
		super(Constant.SERVICE_NAME_UPLOAD);
	}

	@Override
	protected void onHandleIntent(Intent arg0) {
        om = new OperationManager(getBaseContext());
        fm = new FileManager(getBaseContext());
		app = (SDAApplication)this.getApplication();
		
		if(!CUtil.isNetworkAvailable(this)){
			om.removeOperation(Operation.OP_UPLOAD);
			responseConnectError(this.getString(R.string.msg_error_network));
			return;
		}
		
		if(app.getSession()!=null && app.getAuthClient()!=null){
			if(next()){
	            initNotification();
	            upload();
	        }
		}else{
			final LiveAuthClient aClient = new LiveAuthClient(this,Config.CLIENT_ID);
			aClient.initialize(Arrays.asList(Config.SCOPES), new LiveAuthListener(){
	            @Override
	            public void onAuthError(LiveAuthException exception, Object userState) {
	            	om.removeOperation(Operation.OP_UPLOAD);
	            	responseConnectError(UploadOperationService.this.getString(R.string.msg_error_connect));
	            }

	            @Override
	            public void onAuthComplete(LiveStatus status,LiveConnectSession session,Object userState) {
	                if (status==LiveStatus.CONNECTED) {
	                	app.setAuthClient(aClient);
	                	app.setSession(session);
	                    app.setConnectClient(new LiveConnectClient(session));
	                    if(next()){
	                        initNotification();
	                        upload();
	                    }
	                }else{
	                	om.removeOperation(Operation.OP_DOWNLOAD);
	                	responseConnectError(UploadOperationService.this.getString(R.string.msg_error_connect));
	                }
	            }
	        });
		}	
	}
	
	private void upload(){
		File file = new File(op.getPath());
		path = op.getTarget();
		doUpload(file,path);
	}
	
	private boolean next(){
		boolean flag = false;
		List<Operation> ops = om.getOperationReady(Operation.OP_UPLOAD);
		if(ops.size()>0){
			flag = true;
			op = ops.get(0);
		}
		return flag;
	}
	
	private boolean doUpload(final File file,final String path){
		boolean flag = true;
		try{		
			notification.contentView.setTextViewText(R.id.status_text, file.getName());
			notification.contentView.setTextViewText(R.id.status_message, UploadOperationService.this.getString(R.string.notification_uploading));
			notification.contentView.setProgressBar(R.id.status_progress, 100, 0, false);
			notificationManager.notify(Constant.NOTIFICATION_UPLOAD_ID, notification);			
			
			op.setStatus(String.valueOf(Operation.STATUS_PROCESS));
			om.update(op);
			operation = app.getConnectClient().uploadAsync(path,
					file.getName(), 
					file, 
					new LiveUploadOperationListener() {
						int current = 0;
						@Override
						public void onUploadProgress(int totalBytes,int bytesRemaining, LiveOperation operation) {
							int completed = countProgress(totalBytes, bytesRemaining);
							if(completed>=current+5 || completed==100){
								current = completed;
								notification.contentView.setProgressBar(R.id.status_progress, 100, current, false);
								notificationManager.notify(Constant.NOTIFICATION_UPLOAD_ID, notification);
								sendProgress(op.getPath(),current,true);
							}						
						}

						@Override
						public void onUploadFailed(LiveOperationException exception,LiveOperation operation) {
							//om.removeOperation(op.getPath(), Integer.valueOf(op.getAction()));
							op.setStatus(String.valueOf(Operation.STATUS_ERROR));
							om.update(op);
							notification.contentView.setTextViewText(R.id.status_message, UploadOperationService.this.getString(R.string.notification_upload_error));
							notificationManager.notify(Constant.NOTIFICATION_UPLOAD_ID, notification);	
							//TODO prompt that failed to upload a file.
							response(false,getString(R.string.notification_upload_error),path);
							sendProgress(op.getPath(),0,false);
							
							if(next()){
								upload();
					        }else{
					        	//TODO prompt the operation is done.
					        	new FileSyncTask().execute(new String[]{path});
					        }
						}

						@Override
						public void onUploadCompleted(LiveOperation operation) {
							//om.removeOperation(op.getPath(), Integer.valueOf(op.getAction()));	
							JSONObject result = operation.getResult();		
							boolean isDone = !result.has(JsonKeys.ERROR);
							if (!isDone) {						
								op.setStatus(String.valueOf(Operation.STATUS_ERROR));
								om.update(op);
					            notification.contentView.setTextViewText(R.id.status_message, UploadOperationService.this.getString(R.string.notification_upload_error));
								notificationManager.notify(Constant.NOTIFICATION_UPLOAD_ID, notification);									
								response(false,getString(R.string.notification_upload_error),path);
								sendProgress(op.getPath(),0,false);
							}else{								
								op.setStatus(String.valueOf(Operation.STATUS_SUCCESS));
								om.update(op);
								notification.contentView.setTextViewText(R.id.status_message, UploadOperationService.this.getString(R.string.notification_upload_success));
								notificationManager.notify(Constant.NOTIFICATION_UPLOAD_ID, notification);																
								sendProgress(op.getPath(),100,true);
							}								
							
							if(next()){
					        	upload();
					        }else{
					        	//TODO prompt the operation is done.
								new FileSyncTask().execute(new String[]{path});
					        }
						}
					});
			app.setUploadOperation(operation);
		}catch(Exception e){
			Log.e(Constant.TAG, e.getMessage(),e);
		}
		
		return flag;
	}
		
	private void initNotification(){
		notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
		Intent intent = new Intent(this,OperationListActivity.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);		
		
		NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
		builder.setSmallIcon(android.R.drawable.stat_sys_upload);
		Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),R.drawable.ic_notif_upload);
		builder.setLargeIcon(largeIcon);
		
		builder.setContentIntent(pendingIntent);
		builder.setContent(new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_progress));
		notification = builder.getNotification();
		notification.icon = android.R.drawable.stat_sys_upload;
		notification.flags |= Notification.FLAG_AUTO_CANCEL;				
		
		notification.contentView.setProgressBar(R.id.status_progress, 100, 0, false);
		notificationManager.notify(Constant.NOTIFICATION_UPLOAD_ID, notification); 
	}
	
	public class FileSyncTask extends AsyncTask<String, Void, Boolean>{		
		@Override
		protected Boolean doInBackground(String... params) {
			fm.syncFiles(app.getConnectClient(), params[0]);
			return true;
		}
		
		@Override
        protected void onPostExecute(final Boolean isLogin) {
			response(true,null,path);
		}		
	}
	
	private int countProgress(long totalBytes, long bytesRemaining) {
        return (int) (((float)(totalBytes - bytesRemaining)) / totalBytes * 100);
    }
	
	protected void response(boolean isDone, String message, String path) {
		Intent respone = new Intent(Constant.SERVICE_NAME_BASIC);
		respone.putExtra(Constant.SERVICE_PARAM_ID, path);
		respone.putExtra(Constant.SERVICE_PARAM_DONE, isDone);
		respone.putExtra(Constant.SERVICE_PARAM_MSG, message);
		sendBroadcast(respone);
	}
	
	private void sendProgress(String path, int progress,boolean isDone){
		Intent respone = new Intent(Constant.BOARDFAST_UPLOAD_PROGRESS);
		respone.putExtra(Constant.PARAM_PATH, path);
		respone.putExtra(Constant.PARAM_PROGRESS, progress);
		respone.putExtra(Constant.PARAM_DONE, isDone);
		sendBroadcast(respone);
	}
	
	private void responseConnectError(String msg){
		Intent respone = new Intent(Constant.SERVICE_NAME_CONNECT);
		respone.putExtra(Constant.SERVICE_PARAM_ERROR, true);
		respone.putExtra(Constant.SERVICE_PARAM_MSG, msg);
		sendBroadcast(respone);
	}
}
